package com.cskaoyan.javase.oop2._1extends._9override._0introduction;

/**
 * 方法的覆盖/重写
 * 父子类中的成员方法也是可以同名的。那么我们直接创建子类对象，使用子类引用接收。
 * 调用同名方法，这时会体现出子类的行为
 *
 * 那么这里方法是覆盖还是隐藏呢？
 * 我们可以写一个public方法，然后在父类中访问同名成员方法，最后测试调用这个public方法
 * 发现方法调用的结果仍然是子类的行为
 * 这说明方法好像是被覆盖了！
 * 但是这种覆盖不是真正的物理意义上的覆盖，方法不过是方法区的二进制指令合集，它不会消息
 * 这种覆盖是因为"对象名成员方法"的调用机制而导致的。
 * 我们仍然可以在子类中使用super关键字调用父类同名成员方法。（受权限限制）
 *
 * "对象名成员方法"的调用机制
 * 研究这个调用机制从两个角度:
 *      1.研究"对象名点"访问成员方法的访问范围
 *      2.研究"对象名点"访问成员方法的调用结果
 * 当然研究之前,我们要知道,当存在父子类继承关系时,创建对象有三种形式:
 *      1.创建子类对象,用子类引用接收
 *      2.创建父类对象,用父类引用接收
 *      3.创建子类对象,用父类引用接收
 *
 *  首先研究"对象名点成员方法"的访问范围
 *  这样一个访问范围和"对象名点成员变量"的访问范围是一样的，都看引用的数据类型
 *
 *  "对象名点成员方法"的调用结果
 *  通过测试，我们发现"对象名点成员方法"的调用结果
 *  要根据对象的具体类型来决定
 *  正是因为"对象名点成员方法"的调用结果
 *  要根据对象的具体类型来决定
 *  所以
 *  访问同名成员方法，体会为方法的覆盖。
 *
 *
 * @since 09:27
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
       /* Son s = new Son();
        s.test();
        s.invokeTestInFather();
        s.superInvokeTest();*/
        // 1.创建子类对象,用子类引用接收
        Son s = new Son();
        // s.testSon();
        // s.testFather();
        s.test();
        // 2.创建父类对象,用父类引用接收
        Father f = new Father();
        f.test();
        // f.testFather();
        // 3.创建子类对象,用父类引用接收
        Father fs = new Son();
        fs.test();
        // 不能直接访问子类独有成员方法,需要强转
        // ((Son) fs).testSon();
        // fs.testFather();
    }
}

class Father {
    public void test() {
        System.out.println("Father");
    }

    public void testFather() {
        System.out.println("father only");
    }

    /*public void invokeTestInFather() {
        test();
    }*/
}

class Son extends Father {
    public void test() {
        System.out.println("Son");
    }

    public void testSon() {
        System.out.println("son only");
    }
    /*public void superInvokeTest(){
        super.test();
    }*/
}